﻿/*
 * by cansik / Florian
 * Datum: 29.04.2009
 * Zeit: 10:55
 */
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using CML;

namespace Selup
{
	/// <summary>
	/// Selup Updater Core
	/// </summary>
	public class Updater
	{
		public string ConfigFile {get; set;}
		
		public string URL{get; set;}
		public Version ProductVersion{get; set;}
		public string Name{get; set;}
		
		public Updater(String configfile)
		{
			ConfigFile = configfile;
		}
		
		public void ReadConfig()
		{
            Out("reading configuration...", ConsoleColor.Gray);
			CMLReader reader = new CMLReader(ConfigFile);
			reader.ReadFile(false);
			
			URL = reader.GetElement("server").Attributes["url"];
			ProductVersion = new Version(reader.GetElement("info").Attributes["version"]);
			Name = reader.GetElement("info").Attributes["name"];
			
			reader.Close();
            Out("configuration of " + Name, ConsoleColor.White);
		}
		
		public UpdateInformation GetUpdateInformation()
		{
            Out("loading update information...", ConsoleColor.Gray);
			var ui = new UpdateInformation();
			
			string tempFile = DownloadFile(URL + "/" + Name + "/" + "config.txt");
			
			CMLReader reader = new CMLReader(tempFile);
			reader.ReadFile(false);
			
			ui.Name = reader.GetElement("info").Attributes["name"];
			ui.Version = new Version(reader.GetElement("info").Attributes["version"]);
			ui.UpdateFiles = new List<UpdateFile>();
			
			foreach (CMLElement e in reader.ElementsList)
			{
				if (e.Name != "info")
				{
					var uf = new UpdateFile();
					
					uf.source = e.Attributes["source"];
					uf.destination = e.Attributes["destination"];
					
					ui.UpdateFiles.Add(uf);
				}
			}
			
			reader.Close();
            Out("new version is " + ui.Version.ToString(), ConsoleColor.White);
			return ui;
		}
		
		public void Update()
		{
            Out("updating " + Name + "...", ConsoleColor.Gray);

			UpdateInformation info = GetUpdateInformation();
			
			foreach (UpdateFile uf in info.UpdateFiles)
			{
				string file = DownloadFile(URL + "/" + Name + "/" + info.Version.ToString() + "/" + uf.source);

                Out("installing " + Path.GetFileName(uf.destination) + "...", ConsoleColor.White);

				if (File.Exists(uf.destination))
				{
					File.Delete(uf.destination);
				}
				
				File.Copy(file, uf.destination, true);
			}
			
			UpdateConfig(info.Version);
		}
		
		public Boolean UpdateAvailable()
		{
			UpdateInformation info = GetUpdateInformation();
			
			if (info.Version > ProductVersion)
			{
				return true;
			}
			else
			{
				return false;
			}
		}

        private void UpdateConfig(Version newversion)
        {
            CMLWriter writer = new CMLWriter(ConfigFile);
            CMLElement info = new CMLElement("info");
            CMLElement server = new CMLElement("server");

            CMLAttribut name = new CMLAttribut();
            CMLAttribut version = new CMLAttribut();
            CMLAttribut url = new CMLAttribut();

            name.Name = "name";
            version.Name = "version";
            url.Name = "url";

            name.Value = (Name);
            version.Value = newversion.ToString();
            url.Value = URL;

            info.AddAttribut(name);
            info.AddAttribut(version);
            server.AddAttribut(url);

            info.Save();
            server.Save();

            writer.AddElement(info);
            writer.AddElement(server);

            writer.SaveAndClose(false);
        }
		
		private String DownloadFile(string source)
		{
            try
            {
                String tempfile = Path.GetTempFileName();
                System.Net.WebClient client = new WebClient();

                client.DownloadFile(source, tempfile);

                return tempfile;
            }
            catch (Exception ex)
            {
                Out("Error: " + ex.Message, ConsoleColor.Yellow);
                return ex.Message;
            }
		}

        private void Out(string value, ConsoleColor color)
        {
            Console.ForegroundColor = color;
            Console.WriteLine(value);
        }
	}
	
	public struct UpdateInformation
	{
		public String Name;
		public Version Version;
		public List<UpdateFile> UpdateFiles;
		
	}
	
	public struct UpdateFile
	{
		public string source;
		public string destination;
	}
}
